package edu.pku.sei.autounit.core;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.pku.sei.autounit.reflect.Method;
import edu.pku.sei.autounit.tester.MethodGenerator;
import edu.pku.sei.autounit.tester.SimpleMethodGenerator;
import edu.pku.sei.autounit.util.Log;
import edu.pku.sei.autounit.util.NameFactory;
import edu.pku.sei.autounit.util.Statements;


public class TestCase {
	private List<MethodInvocation> elements;
	private String name;
	private String detail;
	private MethodGenerator defaultMethodTester;

	public TestCase(String name,edu.pku.sei.autounit.reflect.Class clas,VariableFactory vf){
		//TODO sequence
	}

	public TestCase(String name,Method method,VariableFactory vf){
		this.name=name;
		this.defaultMethodTester = new SimpleMethodGenerator();
		this.detail = "test "+method.getName();
		NameFactory nf = new NameFactory();
		this.elements =getStrategy(method).generate(method,vf,nf);
	}

	public Statements getCode(Map<String,String> map){
		Statements s = new Statements();
		
		if(detail.equals(""))
			s.insertStatement("@Test");
		else
			s.insertStatement("@Test //"+detail);
		s.insertStatement("public void "+name+"(){");

		Set<Variable> set = new HashSet<Variable>();
		for(MethodInvocation mi:elements){
			s.merge(getInvokeCode(mi,map,set));
			s.insertStatement("\n");
		}
		s.insertStatement("}");
		return s;
	}
	
	private Statements getInvokeCode
		(MethodInvocation mi,Map<String,String> map,Set<Variable> set){
		Statements s = new Statements();
		if(!mi.getMethod().isStatic()&&mi.getRunObject()!=null&&
				!set.contains(mi.getRunObject())){
			s.merge(mi.getRunObject().getInitCode(map));
			set.add(mi.getRunObject());
		}
		for(int i=0;i<mi.getParameters().length;i++){
			if(set.contains(mi.getParameters()[i]))
				continue;
			s.merge(mi.getParameters()[i].getInitCode(map));
			set.add(mi.getParameters()[i]);
		}

		if(!mi.getMethod().hasException())
			s.insertStatement("try{");
		
		StringBuffer sb=new StringBuffer();
		
		if(!mi.getMethod().isStatic()){
			sb.append(mi.getRunObject().getValue());
		}
		else{
			sb.append(mi.getMethod().getDeclaringClass().getName(map));
		}
		
		sb.append("."+mi.getMethod().getName()+"(");
		
			
		for(Variable v:mi.getParameters()){
			sb.append(v.getValue()+",");
		}
		
		String temp = sb.toString();
		if(temp.endsWith(","))
			s.insertStatement(temp.substring(0, temp.length()-1)+");");
		else
			s.insertStatement(temp.substring(0, temp.length())+");");
		
		if(!mi.getMethod().hasException()){
			s.insertStatement("}catch(Throwable t){");
			s.insertStatement("fail();");
			s.insertStatement("}");
		}
		return s;
	}
	
	private MethodGenerator getStrategy(Method method){
		java.lang.Class<?> strategy = method.getStrategy();
		
		if(strategy != null){
			try {
				Object mg = strategy.newInstance();
				if(mg instanceof MethodGenerator)
					return (MethodGenerator) mg;
			} catch (InstantiationException e) {
				Log.findBug("TestCase", "getStrategy", 
						"the generator should have a no parameter constructor");
			} catch (IllegalAccessException e) {
				Log.findBug("TestCase", "getStrategy", 
						"the generator should have a no parameter constructor");
			}
		}
		return defaultMethodTester;
	}
}
